package cn.initcap.concurrency.concurrency.atomic;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import lombok.extern.slf4j.Slf4j;

/**
 * 用于对比LongAdder和AtomicLong的性能
 *
 * @author initcap
 * @date Created in 2018/8/10 AM9:06.
 */
@Slf4j
public class LongAdderVsAtomicLong {

    public static void main(String[] args) {
        testAtomicLongVSLongAdder(10, 10000);
        testAtomicLongVSLongAdder(20, 10000);
        testAtomicLongVSLongAdder(40, 20000);
        testAtomicLongVSLongAdder(40, 200000);
        testAtomicLongVSLongAdder(20, 50000);
    }

    private static void testAtomicLongVSLongAdder(final int threadCount, final int times) {
        try {
            long start = System.currentTimeMillis();
            testLongAdder(threadCount, times);
            long end = System.currentTimeMillis() - start;
            log.info("条件>>>>>>线程数:{}, 单线程操作计数:{}万次", threadCount, times / 10000);
            log.info("结果>>>>>>LongAdder方式增加计数:{}万次,共计耗时:{}", (threadCount * times) / 10000, end);

            long start2 = System.currentTimeMillis();
            testAtomicLong(threadCount, times);
            long end2 = System.currentTimeMillis() - start2;
            log.info("结果>>>>>>AtomicLong方式增加计数:{}万次,共计耗时:{}", (threadCount * times) / 10000, end2);
        } catch (InterruptedException e) {
            log.info("InterruptedException:{}", e);
            Thread.currentThread().interrupt();
        }
    }

    private static void testAtomicLong(final int threadCount, final int times) throws InterruptedException {
        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        AtomicLong atomicLong = new AtomicLong();
        ExecutorService executorService = new ThreadPoolExecutor(0, threadCount, 60L,
                TimeUnit.SECONDS, new SynchronousQueue<>(),
                new ThreadFactoryBuilder().setNameFormat("testAtomicLong").build());
        for (int i = 0; i < threadCount; i++) {
            executorService.execute(() -> {
                for (int j = 0; j < times; j++) {
                    atomicLong.incrementAndGet();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

    private static void testLongAdder(final int threadCount, final int times) throws InterruptedException {
        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        LongAdder longAdder = new LongAdder();
        ExecutorService executorService = new ThreadPoolExecutor(0, threadCount, 60L,
                TimeUnit.SECONDS, new SynchronousQueue<>(),
                new ThreadFactoryBuilder().setNameFormat("testLongAdder").build());
        for (int i = 0; i < threadCount; i++) {
            executorService.execute(() -> {
                for (int j = 0; j < times; j++) {
                    longAdder.increment();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

}
